﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;

namespace Dude.Data.Meta
{
    [Flags]
    public enum MetadataUpdateMode
    {
        /// <summary>
        /// Checks for structure differences
        /// </summary>
        Check = 1,
        /// <summary>
        /// Delete fields and tables from definition if they don't exists in structure
        /// </summary>
        DeleteMissing = 2,
        /// <summary>
        /// Add added fields in database to definition
        /// </summary>
        AppendAdded = 4,
        /// <summary>
        /// Same as Check | DeleteMissing | AppendAdded
        /// </summary>
        FullUpdate = Check | DeleteMissing | AppendAdded
    }

    public abstract class DbMetadataGenerator
    {
        public DbMetadataGenerator()
        {
        }

        public DbProviderFactory ProviderFactory { get; set; }
        public DbConnection Connection { get; set; }
        public DbTransaction Transaction { get; set; }
        
        /// <summary>
        /// Returns DbCommand for SQL select user tables from database
        /// </summary>
        public abstract DbCommand GetShowTablesCommand();

        /// <summary>
        /// Returns DbCommand for SQL select fields for table from database
        /// This command has 1 parameter which should be set to table name
        /// </summary>
        public abstract DbCommand GetShowFieldsCommand();

        public abstract DataModel UpdateDataModel(DataModel original, MetadataUpdateMode updateMode);

        public IEnumerable<DataRow> GetTablesEnumerator()
        {
            DataTable tables = GetTablesTable(null);

            foreach(DataRow row in tables.Rows)
            {
                yield return row;
            }
        }

        public DataTable GetTablesTable(DataTable tables)
        {
            if (tables == null)
                tables = new DataTable("Tables");

            DbCommand cmd = GetShowTablesCommand();
            cmd.Connection = Connection;
            cmd.Transaction = Transaction;

            DbDataAdapter adapter = ProviderFactory.CreateDataAdapter();
            adapter.SelectCommand = cmd;
            adapter.Fill(tables);

            return tables;
        }

        public IEnumerable<DataRow> GetFieldsEnumerator(string tableName)
        {
            DataTable fields = GetFieldsTable(tableName, null);
            foreach (DataRow row in fields.Rows)
            {
                yield return row;
            }
        }

        public DataTable GetFieldsTable(string tableName, DataTable fields)
        {
            if (fields == null)
                fields = new DataTable("Fields");

            DbCommand cmd = GetShowFieldsCommand();
            if (cmd.Parameters.Count != 1)
            {
                throw new Exception("Command GetShowFieldsCommand() must have 1 parameter");
            }
            cmd.Parameters[0].Value = tableName;
            cmd.Connection = Connection;
            cmd.Transaction = Transaction;

            DbDataAdapter adapter = ProviderFactory.CreateDataAdapter();
            adapter.SelectCommand = cmd;
            adapter.Fill(fields);
            return fields;
        }

    }
}
